package com.avengers.core.model;

import com.jfinal.plugin.activerecord.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author yu.wang
 * @since 2018-04-04 下午6:27
 */
public class AvengersActiveRecordPlugin extends ActiveRecordPlugin {
    private static final Logger logger = LoggerFactory.getLogger(AvengersActiveRecordPlugin.class);

    public AvengersActiveRecordPlugin(String configName, DataSource dataSource, int transactionLevel) {
        super(configName, dataSource, transactionLevel);
    }

    public AvengersActiveRecordPlugin(DataSource dataSource) {
        super(dataSource);
    }

    public AvengersActiveRecordPlugin(String configName, DataSource dataSource) {
        super(configName, dataSource);
    }

    public AvengersActiveRecordPlugin(DataSource dataSource, int transactionLevel) {
        super(dataSource, transactionLevel);
    }

    public AvengersActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider, int transactionLevel) {
        super(configName, dataSourceProvider, transactionLevel);
    }

    public AvengersActiveRecordPlugin(IDataSourceProvider dataSourceProvider) {
        super(dataSourceProvider);
    }

    public AvengersActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider) {
        super(configName, dataSourceProvider);
    }

    public AvengersActiveRecordPlugin(IDataSourceProvider dataSourceProvider, int transactionLevel) {
        super(dataSourceProvider, transactionLevel);
    }

    public AvengersActiveRecordPlugin(Config config) {
        super(config);
    }

    @Override
    public ActiveRecordPlugin addMapping(String tableName, Class<? extends Model<?>> modelClass) {
        initConfigName(modelClass);
        return super.addMapping(tableName, modelClass);
    }

    @Override
    public ActiveRecordPlugin addMapping(String tableName, String primaryKey, Class<? extends Model<?>> modelClass) {
        initConfigName(modelClass);
        return super.addMapping(tableName, primaryKey, modelClass);
    }

    private void initConfigName(Class<? extends Model<?>> modelClass) {
        String configName = this.getConfig().getName();
        if (DbKit.MAIN_CONFIG_NAME.equals(configName)) {
            return;
        }
        try {
            String methodName = "setConfigName";
            Method method = getTargetMethod(modelClass, methodName, String.class);

            if (null != method) {
                method.setAccessible(true);
                if (Modifier.isStatic(method.getModifiers())) {
                    method.invoke(null, configName);
                } else {
                    method.invoke(modelClass.newInstance(), configName);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    private Method getTargetMethod(Class<?> targetClass, String methodName, Class<?>... parameterTypes) {
        Method method = null;
        try {
            method = targetClass.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            if (AbstractEnhancerModel.class.getSimpleName().equals(targetClass.getSimpleName())) {
                return null;
            }
            return getTargetMethod(targetClass.getSuperclass(), methodName, parameterTypes);
        } catch (Exception e) {
            logger.error("get target method_{} from class_{} error: {}", methodName, targetClass.getSimpleName(), e.getMessage(), e);
        }
        return method;
    }
}
